/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.hzins.zhike.okhttp3.simple;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 描述:
 *
 * @author tianyuliang
 * @version $Id: SimpleOkHttpUtils.java, v0.1 2022/4/14
 */
@Slf4j
public class SimpleOkHttpUtils {

    /**
     * 发起Get请求
     *
     * @param url url
     * @return 响应结果
     */
    public static String get(String url) {
        Request request = createGetRequest(url, new HashMap<>(), new HashMap<>());
        return execute(request);
    }

    /**
     * 发起Get请求
     *
     * @param url    url
     * @param params 参数
     * @return 响应结果
     */
    public static String get(String url, Map<String, Object> params) {
        Request request = createGetRequest(url, params, new HashMap<>());
        return execute(request);
    }

    /**
     * 发起Get请求
     *
     * @param url     url
     * @param headers headers
     * @return 响应结果
     */
    public static String getWithHeaders(String url, Map<String, String> headers) {
        Request request = createGetRequest(url, new HashMap<>(), headers);
        return execute(request);
    }

    /**
     * 发起Get请求
     *
     * @param url     url
     * @param params  参数
     * @param headers headers
     * @return 响应结果
     */
    public static String get(String url, Map<String, Object> params, Map<String, String> headers) {
        Request request = createGetRequest(url, params, headers);
        return execute(request);
    }

    /**
     * 发起 Post请求, 使用form表单参数
     *
     * @param url url
     * @return 响应结果
     */
    public static String post(String url) {
        Request request = createPostRequest(url, new HashMap<>(), new HashMap<>());
        return execute(request);
    }

    /**
     * 发起 Post请求, 使用form表单参数
     *
     * @param url    url
     * @param params 参数
     * @return 响应结果
     */
    public static String post(String url, Map<String, Object> params) {
        Request request = createPostRequest(url, params, new HashMap<>());
        return execute(request);
    }

    /**
     * 发起 Post请求, 使用form表单参数
     *
     * @param url     url
     * @param headers headers
     * @return 响应结果
     */
    public static String postWithHeaders(String url, Map<String, String> headers) {
        Request request = createPostRequest(url, new HashMap<>(), headers);
        return execute(request);
    }

    /**
     * 发起 Post请求, 使用form表单参数
     *
     * @param url    url
     * @param params 参数
     * @return 响应结果
     */
    public static String post(String url, Map<String, Object> params, Map<String, String> headers) {
        Request request = createPostRequest(url, params, headers);
        return execute(request);
    }

    /**
     * 发起 post请求, 使用json参数
     *
     * @param url  url
     * @param json json参数
     * @return resp
     */
    public static String post(String url, String json, Map<String, String> headers) {
        Request request = createPostJsonRequest(url, json, headers);
        return execute(request);
    }

    /**
     * [异步] 发起Get请求
     *
     * @param url      url
     * @param callback 回调方法
     */
    public static void getAsync(String url, Callback callback) {
        Request request = createGetRequest(url, new HashMap<>(), new HashMap<>());
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * [异步] 发起Get请求
     *
     * @param url      url
     * @param params   参数
     * @param callback 回调方法
     */
    public static void getAsync(String url, Map<String, Object> params, Callback callback) {
        Request request = createGetRequest(url, params, new HashMap<>());
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * [异步] 发起Get请求
     *
     * @param url      url
     * @param headers  参数
     * @param callback 回调方法
     */
    public static void getAsyncWithHeader(String url, Map<String, String> headers, Callback callback) {
        Request request = createGetRequest(url, new HashMap<>(), headers);
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * [异步] 发起Get请求
     *
     * @param url      url
     * @param params   参数
     * @param callback 回调方法
     */
    public static void getAsync(String url, Map<String, Object> params, Map<String, String> headers, Callback callback) {
        Request request = createGetRequest(url, params, headers);
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * [异步] 发起 Post请求
     *
     * @param url    url
     * @param params 参数
     */
    public static void postAsync(String url, Map<String, Object> params, Map<String, String> headers, Callback callback) {
        Request request = createPostRequest(url, params, headers);
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * [异步] 发起 post请求, 使用json参数
     *
     * @param url  url
     * @param json json参数
     */
    public static void postAsync(String url, String json, Map<String, String> headers, Callback callback) {
        Request request = createPostJsonRequest(url, json, headers);
        InitOkHttpClient.getInstance().newCall(request).enqueue(callback);
    }

    /**
     * 同步执行 http请求
     *
     * @param request request对象
     * @return 响应结果
     */
    public static String execute(Request request) {
        String result = "";
        try {
            Response response = InitOkHttpClient.getInstance().newCall(request).execute();
            int code = response.code();
            if (code != SimpleConstants.SC_OK) {
                String msg = response.message();
                log.warn("数据处理失败, code={}, url={}, msg={}", code, request.url(), msg);
                return result;
            }

            if (response.body() != null) {
                result = response.body().string(); //TODO 调用“response.body().string()”会触发“response.close()”关闭流
            }
        } catch (IOException e) {
            log.error("请求IO异常, url={}", request.url(), e);
        } catch (Exception e) {
            log.error("请求Exception异常, url={}", request.url(), e);
        } catch (OutOfMemoryError e) {
            log.error("请求OutOfMemoryError异常, url={}", request.url(), e);
        }
        return result;
    }

    /**
     * 关闭ThreadPoolExecutor
     */
    public static void shutdown(ThreadPoolExecutor executor) {
        if (executor != null) {
            try {
                executor.shutdown();
            } catch (Exception e) {
                log.error("executor shutdown error.", e);
            }
        }
    }

    /**
     * 关闭ThreadPoolExecutor
     */
    public static void shutdownSelf() {
        OkHttpClient okHttpClient = InitOkHttpClient.getInstance();
        if (okHttpClient != null) {
            try {
                if (okHttpClient.cache() != null) {
                    okHttpClient.cache().close();
                }
            } catch (Exception e) {
                log.error("okHttpClient shutdown error.", e);
            }
        }
    }

    /**
     * Get请求, 构造 Call对象
     *
     * @param url    请求url
     * @param params 请求参数
     * @return Call
     */
    private static Request createGetRequest(String url, Map<String, Object> params, Map<String, String> headers) {

        Request.Builder builder = new Request.Builder();
        Request request = builder.url(url).build();
        createFormHeaders(builder, headers);
        // 设置参数
        HttpUrl httpUrl = createHttpUrl(request, params);
        builder.url(httpUrl).build();

        return builder.build();
    }

    /**
     * Post请求, 构造 Call对象
     *
     * @param url    请求url
     * @param params 请求参数
     * @return Call
     */
    private static Request createPostRequest(String url, Map<String, Object> params, Map<String, String> headers) {
        Request.Builder builder = new Request.Builder();
        builder.post(createFormBody(params));
        createFormHeaders(builder, headers);
        builder.url(url);
        return builder.build();
    }

    /**
     * Post请求, 构造 Call对象
     *
     * @param url  请求url
     * @param json 请求参数
     * @return Call
     */
    private static Request createPostJsonRequest(String url, String json, Map<String, String> headers) {
        Request.Builder builder = new Request.Builder();
        builder.post(RequestBody.create(SimpleConstants.MEDIA_TYPE, json));
        createFormHeaders(builder, headers);
        builder.url(url);
        return builder.build();
    }

    /**
     * 设置headers
     *
     * @param builder
     * @param headers
     */
    private static void createFormHeaders(Request.Builder builder, Map<String, String> headers) {
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                builder.addHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    /**
     * 为 get请求设置参数
     *
     * @param request request对象
     * @param params  请求参数
     * @return 设置了参数的 HttpUrl对象
     */
    private static HttpUrl createHttpUrl(Request request, Map<String, Object> params) {
        HttpUrl.Builder urlBuilder = request.url().newBuilder();
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                urlBuilder.addQueryParameter(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        return urlBuilder.build();
    }

    /**
     * 为 post请求设置参数
     *
     * @param params 请求参数
     * @return FormBody
     */
    private static FormBody createFormBody(Map<String, Object> params) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                builder.add(entry.getKey(), String.valueOf(entry.getValue()));
            }
        }
        return builder.build();
    }


}